package org.bminfo.migle.wrapper;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.bminfo.sequence.FastaSeq;
import org.bminfo.sequence.RawInput;

import org.bminfo.migle.filemanage.FileOperate;
import org.bminfo.migle.parser.CommandExecutor;
import org.bminfo.migle.parser.PointMut;

public class MiRandaWrapper{

	/**
	 * The reference sequence end with "reference"
	 * The mutated sequence end with mut plus a number.
	 * like:	|build=129|Reference
	 * 			mol=Genomic|build=129|mut1
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
//
//		MiRandaWrapper mr = new MiRandaWrapper();
//		String infile = "3utr.fasta";
//		HashMap<String, Double> RankedmiRNA = mr.getRankedLossEvent(infile, "C");
//		
//		for(String miRNA: RankedmiRNA.keySet()){
//			System.out.println(miRNA + "\t" + RankedmiRNA.get(miRNA));
//		}
		
		MiRandaWrapper wr = new MiRandaWrapper();
		wr.setMirandaRltFilePath("mirandaRlt.txt", "D:/2mirandaRlt.txt");
		System.out.println(wr.getUniqueMutIndex());
		wr.parseAnalysisRltFile();
//		System.out.println(wr.getLossEnvents("mut1"));
	}
	
	String miGLE_home = "";
	public String moopPath = "";
	String tempRoot = "";
	String folderName = "";
	public String tempPath = "";
	
	public void setMirandaPath(String path, String foldername){
		miGLE_home = path.replace("\\", "/");
		moopPath = miGLE_home + "WEB-INF/classes/org/bminfo/migle/miGLE/";
		tempRoot = miGLE_home + "temp/";
		folderName = foldername;
		tempPath = tempRoot + folderName + "/";	
		
		System.out.println(foldername);
		System.out.println(tempPath);
		System.out.println(moopPath);
	}


	public HashMap<String, Double> getRankedLossEvent(String miGLE_path, String path, String infile, String referenceAllele, String parameter, HashMap<String, String> snpInfo) throws IOException {
//		Get dbSNP sequence
		
//		FastaSeq fasta = new FastaSeq(infile, "DNA");
//		String seq = fasta.GetFirstSequence().seqString();
//		String title = fasta.GetFirstSequence().getName();
//		
//		System.out.println(title);
//		System.out.println(seq);
//		System.out.println(path);
//		System.out.println(infile);
//
//
////		convert 
//		PointMut pm = new PointMut();
//		HashMap<String, String> snpInfo = PointMut.getAllelesType(title);
//		
//		System.out.println(snpInfo);
//
//		pm.buildAnalysisFile(path, title, seq, snpInfo, referenceAllele);

		String migle_path = miGLE_path.replace("\\", "/") + "WEB-INF/classes/org/bminfo/migle/miGLE/";
		String cmd = "\"" + migle_path + "miranda\" \"" + migle_path + "hsa-mature-miR.fasta\" " 
					+ "pointmut " + parameter + " -out " + "mirandaRlt.txt";
		System.out.println(cmd);
		
		CommandExecutor exe = new CommandExecutor();
		exe.cmdExec(cmd, path);
		
//		MigleServerImpl step1 = new MigleServerImpl();

//		step1.cmdExec("miranda.exe hsa-mature-miR.fasta pointmut -sc 0 -en  0 -out snp.miranda.rlt");

		int iRangeLeft = Integer.parseInt(snpInfo.get("position"));
		
		int maxAlleleLenght = Integer.parseInt(snpInfo.get("maxAlleleLenght"));
		int iRangeRight = iRangeLeft + maxAlleleLenght;


		setMirandaRltFilePath("./", path + "mirandaRlt.txt");

		HashMap<String, String> sets = getSettings();
		RawInput rin = new RawInput();


		ArrayList<HashMap<String, String>> hotInters = new ArrayList<HashMap<String, String>>();
		for(HashMap<String,String> inter: interactions){

			int iTargetStart = Integer.parseInt(inter.get("start"));
			int iTargetEnd = Integer.parseInt(inter.get("end"));

			if(iRangeLeft >= iTargetStart && iRangeRight <= iTargetEnd ){
				//				System.out.println("Include");
			}else if(iRangeRight > iTargetStart && iRangeLeft <= iTargetStart){
				//				System.out.println("Right overlap");
			}else if(iRangeLeft > iTargetStart && iRangeLeft < iTargetEnd){
				//				System.out.println("Left overlap");
			}else{
				//				System.out.println("No overlap");
				continue;
			}
			hotInters.add(inter);			
		}

		HashMap<String, Double> dd = new HashMap<String, Double>();
		for(HashMap<String, String> inter: hotInters){
			String miRNA = inter.get("miRNA");
			if(!dd.containsKey(miRNA)){
				dd.put(miRNA, 0.0);
			}
		}

		for(String microRNA: dd.keySet()){
			double dRef = 0.0;
			double dMut = 0.0;
			for(HashMap<String, String> inter: hotInters){
				if(inter.get("miRNA").equalsIgnoreCase(microRNA)){
					if(inter.get("seqIndex").equalsIgnoreCase("reference"))
						dRef = Double.parseDouble(inter.get("energy"));

					if(inter.get("seqIndex").equalsIgnoreCase("mut1"))
						dMut = Double.parseDouble(inter.get("energy"));
				}
			}
			if(dMut == dRef){
				dd.put(microRNA, 0.0);
			}else
				dd.put(microRNA, -dRef*dRef/(dMut - dRef));
		}


		HashMap<String, Double> sortedData = rin.sortHashMapByValue(dd);


		return sortedData;
	}

	public ArrayList<HashMap<String, String>> getLossEnvents(String mutSeqIndex) {
		ArrayList<HashMap<String, String>> events = new ArrayList<HashMap<String, String>>();
		for(HashMap<String, String> refInter: interactions){
			if(!refInter.get("seqIndex").equalsIgnoreCase("reference"))
				continue;
			boolean loss = true;
			for(HashMap<String, String> inter: interactions){
				if(!inter.get("seqIndex").equalsIgnoreCase(mutSeqIndex))
					continue;

				if(refInter.get("miRNA").equals(inter.get("miRNA"))){
					loss = false;
				}
			}

			if(loss){
				events.add(refInter);
			}
		}

		return events;
	}

	public ArrayList<HashMap<String, String>> getGainEnvents(String mutSeqIndex) {
		ArrayList<HashMap<String, String>> events = new ArrayList<HashMap<String, String>>();
		for(HashMap<String, String> refInter: interactions){
			if(!refInter.get("seqIndex").equalsIgnoreCase(mutSeqIndex))
				continue;
			boolean gain = true;

			for(HashMap<String, String> inter: interactions){
				if(!inter.get("seqIndex").equalsIgnoreCase("reference"))
					continue;

				if(refInter.get("miRNA").equals(inter.get("miRNA"))){
					gain = false;
				}
			}

			if(gain){
				events.add(refInter);
			}
		}

		return events;
	}

	private HashMap<String, Integer> getUniqueMutIndex() {
		HashMap<String, Integer> uniqueMutIndex = new HashMap<String, Integer>();
		Pattern pMutIndex = Pattern.compile("mut\\d+", Pattern.CASE_INSENSITIVE);
		for(HashMap<String,String> inter: interactions){
			String seqIndex = inter.get("seqIndex");
			if(!uniqueMutIndex.containsKey(seqIndex)){
				uniqueMutIndex.put(seqIndex, 1);
			}else{
				uniqueMutIndex.put(seqIndex, uniqueMutIndex.get(seqIndex) + 1);
			}
		}
		return uniqueMutIndex;
	}
	private String strMirandaRltFilePath = null;
	private ArrayList<String> lines = null;
	private String strVersion;
	HashMap<String, String> settings = new HashMap<String, String>();
	private ArrayList<HashMap<String, String>> interactions = new ArrayList<HashMap<String,String>>();

	public ArrayList<HashMap<String, String>> getInteractions() {
		return interactions;
	}

	public HashMap<String, String> getSettings() {
		return settings;
	}

	public String getVersion() {
		return strVersion;
	}

	private void setMirandaRltFilePath(String fastaFile, String filePath) {
		getSequences(fastaFile);
		strMirandaRltFilePath = filePath;
		parseAnalysisRltFile();
	}

	private void getSequences(String fastaFile) {


	}
	private void parseAnalysisRltFile() {
		RawInput rin = new RawInput();
		lines  = rin.GetListByEachLine(strMirandaRltFilePath, true);
		parseVersion();
		parseSettings();
		parseScanResults();
	}

	private void parseScanResults() {

		interactions = new ArrayList<HashMap<String,String>>();

		Pattern pPerformingScan = Pattern.compile("^Performing Scan: (.*?) vs (.*?)\\|(Reference|mut\\d+)",
				java.util.regex.Pattern.CASE_INSENSITIVE);

		Pattern pScoreForHit = Pattern.compile("^Scores for this hit:",
				java.util.regex.Pattern.CASE_INSENSITIVE);

		Pattern pNoHit = Pattern.compile("^No Hits Found above Threshold");

		Pattern pEnergy = Pattern.compile("^\\s+Energy:\\s+(.*?)\\s+kCal/Mol", Pattern.CASE_INSENSITIVE);

		String miRNAName = "";
		String seqName = "";
		String seqIndex = "";
		String interDetail = "";
		for(int i =0; i < lines.size(); i++){
			String line = lines.get(i);
			Matcher mPscan = pPerformingScan.matcher(line);
			if(mPscan.find()){
				miRNAName = "";
				seqName = "";
				seqIndex = "";


				miRNAName = mPscan.group(1);
				seqName = mPscan.group(2);
				seqIndex = mPscan.group(3);
				//				System.out.println(mPscan.group(1) +"\t" + mPscan.group(3) + "\t" + mPscan.group(2) );
				continue;
			}

			Matcher mScoreForHit = pScoreForHit.matcher(line);
			if(mScoreForHit.find()){
				Matcher mNoHit = pNoHit.matcher(lines.get(i+1));
				if(mNoHit.find()){
					System.out.println("No hit");
				}else{
					interDetail = "";
					String energy = "";
					for(int j = i-10; j < i - 1; j++){
						//						System.out.println(lines.get(j));
						interDetail += lines.get(j) + "\n";
					}

					Matcher mEnergy = pEnergy.matcher(lines.get(i - 2));
					if(mEnergy.find()){
						energy = mEnergy.group(1);
					}


					String[] fields = lines.get(i + 1).split("\t");
					String[] iStartEnd = fields[6].split("\\s+");
					//					System.out.println(miRNAName + "\t" + seqIndex + "\t" +iStartEnd[0]);
					HashMap<String,String> inter = new HashMap<String,String>();
					inter.put("miRNA", miRNAName);
					inter.put("seqIndex", seqIndex);
					inter.put("seqName", seqName);
					inter.put("start", iStartEnd[0]);
					inter.put("end", iStartEnd[1]);
					inter.put("interDetails", interDetail);
					inter.put("energy", energy);
					interactions.add(inter);


				}
			}
		}
	}

	private void parseSettings() {
		Pattern pSetting = Pattern.compile("^(.*?):\t+(.*)$");
		for(int i = 23; i< 31; i++){
			Matcher mSetting = pSetting.matcher(lines.get(i));
			if(mSetting.find()){
				settings.put(mSetting.group(1), mSetting.group(2));
			}
		}

	}

	private void parseVersion() {
		Pattern pVersion = Pattern.compile("^miRanda v(\\d+.\\d+)");
		Matcher mVersion = pVersion.matcher(lines.get(3));
		//		System.out.println(lines.get(3));
		if(mVersion.find()){
			strVersion = mVersion.group(1);
		}else
			strVersion = "NA";

	}
	
	//By Xinyi Liu
	
	public void miranda(String go, String ge, String en, String sc, String snp) throws IOException {

		///* These codes is for windows with perl scripts
		 
		String cmd_Miranda = "\"" + moopPath + "miranda" + "\" \"" + moopPath + "hsa-mature-miR.fasta" + "\" "
								+ "pointmut" + " -go " + go +" -ge " + ge + " -en " + en + " -sc " + sc
								+ " -out " + "mirandaRlt.txt";
		
		String cmd_ParMirRlt = "perl " + "\"" + moopPath + "parMirRlt.pl"
								+ "\" -snp " + snp + " " + "mirandaRlt.txt"
								+ " " + "seq.fasta"	+ " ./";
		
		String cmd_GetTarget = "\"" + moopPath + "getTarget " + "\" " + "parseRlt.txt" + " "
								+ " rtable.txt report.txt moopsbar.js " + " \""
								+ moopPath + "moopsbarTemplate.js" + "\"";
//*/

/* These codes is for linux with perl scripts
		 
		String cmd_Miranda = "miranda" + " " + moopPath + "hsa-mature-miR.fasta"
								+ " " + tempPath + "pointmut"
								+ " -go " + go +" -ge " + ge + " -en " + en + " -sc " + sc
								+ " -out " + tempPath + "mirandaRlt.txt";
		
		String cmd_ParMirRlt = "perl " + moopPath + "parMirRlt.pl"
								+ " -snp " + snp + " " + tempPath + "mirandaRlt.txt"
								+ " " + tempPath + "seq.fasta"
								+ " " + tempPath;
		
		String cmd_GetTarget = "getTarget " + tempPath + "parseRlt.txt" + " "
								+ tempPath + "rtable.txt" + " "
								+ tempPath + "report.txt" + " "
								+ tempPath + "moopsbar.js" + " "
								+ moopPath + "moopsbarTemplate.js";
*/
		
/* These codes is for windows and linux with executable files
 
		String cmd_Miranda = "miranda " + moopPath + "hsa-mature-miR.fasta"
		+ " " + tempPath + "pointmut"
		+ " -go " + go +" -ge " + ge + " -en " + en + " -sc " + sc
		+ " -out " + tempPath + "mirandaRlt.txt";

		
		String cmd_ParMirRlt = "parMirRlt "
		+ "-snp " + snp + " " + tempPath + "mirandaRlt.txt"
		+ " " + tempPath + "seq.fasta"
		+ " " + tempPath;
		
		String cmd_GetTarget = "getTarget " + tempPath + "parseRlt.txt" + " "
		+ tempPath + "rtable.txt" + " "
		+ tempPath + "report.txt" + " "
		+ tempPath + "moopsbar.js" + " "
		+ moopPath + "moopsbarTemplate.js";
*/

		System.out.println(cmd_Miranda);
		System.out.println(cmd_ParMirRlt);
		System.out.println(cmd_GetTarget);
		
//		System.out.println(miGLE_home);
		
		CommandExecutor exe = new CommandExecutor();
		
		if(snp.equals("n")){
			exe.cmdExec(cmd_Miranda, tempPath);
			exe.cmdExec(cmd_ParMirRlt, tempPath);
			exe.cmdExec(cmd_GetTarget, tempPath);
		}else{
			exe.cmdExec(cmd_Miranda, tempPath);
		}
	}
			
	public void copyMigleFile(){
		FileOperate fo = new FileOperate();
		fo.copyFile(moopPath + "showmoops.jsp", tempPath + "showmoops.jsp");
		fo.copyFile(moopPath + "nchart.js", tempPath + "nchart.js");
		fo.copyFile(moopPath + "canvaschart.css", tempPath + "canvaschart.css");
		fo.copyFile(moopPath + "cygwin1.dll", tempPath + "cygwin1.dll");
		fo.copyFile(moopPath + "load.jsp", tempPath + "load.jsp");		
	}
}
